package service

import (
	"encoding/json"
	"errors"
	"fitness/go-admin/internal/model"
	"fitness/go-admin/internal/repository"
	"fitness/go-admin/pkg/cache"
	"fmt"
	"time"
)

// ==================== 统计服务接口 ====================

type StatisticsService interface {
	// 综合统计
	GetOverview(date string) (*model.OverviewResp, error)
	GetTrends(req *model.TrendsQueryReq) (*model.TrendsResp, error)

	// 会员统计
	GetMemberGrowth(req *model.StatisticsQueryReq) (*model.MemberGrowthResp, error)
	GetMemberDistribution(req *model.MemberDistributionReq) (*model.MemberDistributionResp, error)

	// 课程统计
	GetCourseRanking(req *model.CourseRankingReq) (*model.CourseRankingResp, error)
	GetCourseBookingTrends(courseID *uint, req *model.StatisticsQueryReq) (*model.CourseBookingTrendsResp, error)
	GetTimeslotStats(req *model.StatisticsQueryReq) (*model.TimeslotStatsResp, error)

	// 教练统计
	GetCoachWorkload(req *model.CoachWorkloadReq) (*model.CoachWorkloadResp, error)
	GetCoachRanking(req *model.CourseRankingReq) (*model.CoachRankingResp, error)

	// 营收统计
	GetRevenueOverview(req *model.StatisticsQueryReq) (*model.RevenueOverviewResp, error)
	GetRevenueTrends(req *model.RevenueQueryReq) (*model.RevenueTrendsResp, error)
	GetConsumptionStats(req *model.StatisticsQueryReq, consumeType *string) (*model.ConsumptionStatsResp, error)
}

type statisticsService struct {
	statsRepo repository.StatisticsRepository
}

func NewStatisticsService(statsRepo repository.StatisticsRepository) StatisticsService {
	return &statisticsService{
		statsRepo: statsRepo,
	}
}

// ==================== 综合统计实现 ====================

func (s *statisticsService) GetOverview(dateStr string) (*model.OverviewResp, error) {
	// 尝试从缓存获取
	cacheKey := fmt.Sprintf("stats:overview:%s", dateStr)
	if cached, err := cache.Get(cacheKey); err == nil {
		var resp model.OverviewResp
		if err := json.Unmarshal([]byte(cached), &resp); err == nil {
			return &resp, nil
		}
	}

	// 解析日期
	var targetDate time.Time
	var err error
	if dateStr == "" {
		targetDate = time.Now()
	} else {
		targetDate, err = time.Parse("2006-01-02", dateStr)
		if err != nil {
			return nil, errors.New("日期格式错误")
		}
	}

	// 并发获取各项数据
	resp := &model.OverviewResp{
		Date: targetDate.Format("2006-01-02"),
	}

	// 会员统计
	totalMembers, _ := s.statsRepo.GetTotalMembers()
	activeMembers, _ := s.statsRepo.GetActiveMembersCount()
	expiredMembers, _ := s.statsRepo.GetExpiredMembersCount()

	// 今日新增会员
	startOfDay := time.Date(targetDate.Year(), targetDate.Month(), targetDate.Day(), 0, 0, 0, 0, targetDate.Location())
	endOfDay := startOfDay.Add(24 * time.Hour)
	newToday, _ := s.statsRepo.GetNewMembersCount(startOfDay, endOfDay)

	// 计算增长率（与昨天对比）
	yesterdayStart := startOfDay.Add(-24 * time.Hour)
	yesterdayEnd := startOfDay
	newYesterday, _ := s.statsRepo.GetNewMembersCount(yesterdayStart, yesterdayEnd)

	growthRate := 0.0
	if newYesterday > 0 {
		growthRate = float64(newToday-newYesterday) / float64(newYesterday) * 100
	}

	resp.Members = model.MemberOverview{
		Total:      totalMembers,
		NewToday:   newToday,
		Active:     activeMembers,
		Expired:    expiredMembers,
		GrowthRate: growthRate,
	}

	// 课程统计
	totalCourses, _ := s.statsRepo.GetTotalCourses()
	bookingsToday, _ := s.statsRepo.GetTodayBookingsCount(targetDate)
	completedToday, _ := s.statsRepo.GetCompletedBookingsCount(targetDate)

	attendanceRate := 0.0
	if bookingsToday > 0 {
		attendanceRate = float64(completedToday) / float64(bookingsToday) * 100
	}

	resp.Courses = model.CourseOverview{
		Total:          totalCourses,
		BookingsToday:  bookingsToday,
		CompletedToday: completedToday,
		AttendanceRate: attendanceRate,
	}

	// 教练统计
	totalCoaches, _ := s.statsRepo.GetTotalCoaches()
	activeCoaches, _ := s.statsRepo.GetActiveCoachesCount()

	avgBookings := 0.0
	if activeCoaches > 0 && bookingsToday > 0 {
		avgBookings = float64(bookingsToday) / float64(activeCoaches)
	}

	resp.Coaches = model.CoachOverview{
		Total:       totalCoaches,
		Active:      activeCoaches,
		AvgBookings: avgBookings,
	}

	// 营收统计
	totalRevenue, _ := s.statsRepo.GetTotalRevenue()
	todayRevenue, _ := s.statsRepo.GetRevenueByDateRange(startOfDay, endOfDay)

	// 本月营收
	monthStart := time.Date(targetDate.Year(), targetDate.Month(), 1, 0, 0, 0, 0, targetDate.Location())
	monthEnd := monthStart.AddDate(0, 1, 0)
	thisMonthRevenue, _ := s.statsRepo.GetRevenueByDateRange(monthStart, monthEnd)

	// 营收增长率
	lastMonthStart := monthStart.AddDate(0, -1, 0)
	lastMonthEnd := monthStart
	lastMonthRevenue, _ := s.statsRepo.GetRevenueByDateRange(lastMonthStart, lastMonthEnd)

	revenueGrowthRate := 0.0
	if lastMonthRevenue > 0 {
		revenueGrowthRate = (thisMonthRevenue - lastMonthRevenue) / lastMonthRevenue * 100
	}

	resp.Revenue = model.RevenueOverview{
		Total:      totalRevenue,
		Today:      todayRevenue,
		ThisMonth:  thisMonthRevenue,
		GrowthRate: revenueGrowthRate,
	}

	// 会员卡统计
	activeCards, _ := s.statsRepo.GetActiveCardsCount()
	totalBalance, _ := s.statsRepo.GetTotalCardsBalance()
	expireSoon, _ := s.statsRepo.GetExpiringSoonCardsCount(7) // 7天内到期

	resp.Cards = model.MembershipCardOverview{
		TotalActive:  activeCards,
		TotalBalance: totalBalance,
		ExpireSoon:   expireSoon,
	}

	// 缓存结果
	if data, err := json.Marshal(resp); err == nil {
		_ = cache.SetWithExpire(cacheKey, string(data), model.CacheOverviewDuration)
	}

	return resp, nil
}

func (s *statisticsService) GetTrends(req *model.TrendsQueryReq) (*model.TrendsResp, error) {
	// 尝试从缓存获取
	cacheKey := fmt.Sprintf("stats:trends:%s:%s:%s:%s", req.Metric, req.Period, req.StartDate, req.EndDate)
	if cached, err := cache.Get(cacheKey); err == nil {
		var resp model.TrendsResp
		if err := json.Unmarshal([]byte(cached), &resp); err == nil {
			return &resp, nil
		}
	}

	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	resp := &model.TrendsResp{
		Metric: req.Metric,
		Period: req.Period,
	}

	switch req.Metric {
	case model.MetricMembers:
		// 会员增长趋势
		growthData, err := s.statsRepo.GetMemberGrowthByDate(startDate, endDate, req.Period)
		if err != nil {
			return nil, err
		}

		var dataPoints []model.TrendDataPoint
		var total, max, min float64
		min = -1

		for _, data := range growthData {
			value := float64(data.NewMembers)
			total += value
			if value > max {
				max = value
			}
			if min < 0 || value < min {
				min = value
			}

			dataPoints = append(dataPoints, model.TrendDataPoint{
				Date:       data.Date,
				Value:      value,
				Cumulative: float64(data.Cumulative),
			})
		}

		avg := 0.0
		if len(dataPoints) > 0 {
			avg = total / float64(len(dataPoints))
		}

		resp.DataPoints = dataPoints
		resp.Summary = model.TrendSummary{
			Total: total,
			Avg:   avg,
			Max:   max,
			Min:   min,
		}

	case model.MetricRevenue:
		// 营收趋势
		trends, err := s.statsRepo.GetRevenueTrends(startDate, endDate, req.Period, "all")
		if err != nil {
			return nil, err
		}

		var dataPoints []model.TrendDataPoint
		var total, max, min float64
		min = -1
		var cumulative float64

		for _, trend := range trends {
			value := trend.TotalRevenue
			total += value
			cumulative += value
			if value > max {
				max = value
			}
			if min < 0 || value < min {
				min = value
			}

			dataPoints = append(dataPoints, model.TrendDataPoint{
				Date:       trend.Date,
				Value:      value,
				Cumulative: cumulative,
			})
		}

		avg := 0.0
		if len(dataPoints) > 0 {
			avg = total / float64(len(dataPoints))
		}

		resp.DataPoints = dataPoints
		resp.Summary = model.TrendSummary{
			Total: total,
			Avg:   avg,
			Max:   max,
			Min:   min,
		}

	default:
		return nil, errors.New("不支持的指标类型")
	}

	// 缓存结果
	if data, err := json.Marshal(resp); err == nil {
		_ = cache.SetWithExpire(cacheKey, string(data), model.CacheTrendsDuration)
	}

	return resp, nil
}

// ==================== 会员统计实现 ====================

func (s *statisticsService) GetMemberGrowth(req *model.StatisticsQueryReq) (*model.MemberGrowthResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	groupBy := req.GroupBy
	if groupBy == "" {
		groupBy = "day"
	}

	growthData, err := s.statsRepo.GetMemberGrowthByDate(startDate, endDate, groupBy)
	if err != nil {
		return nil, err
	}

	// 计算统计数据
	var totalNew int64
	for _, data := range growthData {
		totalNew += data.NewMembers
	}

	dailyAvg := 0.0
	if len(growthData) > 0 {
		dailyAvg = float64(totalNew) / float64(len(growthData))
	}

	return &model.MemberGrowthResp{
		Period:     req.StartDate + " ~ " + req.EndDate,
		GroupBy:    groupBy,
		TotalNew:   totalNew,
		DailyAvg:   dailyAvg,
		GrowthData: growthData,
	}, nil
}

func (s *statisticsService) GetMemberDistribution(req *model.MemberDistributionReq) (*model.MemberDistributionResp, error) {
	var startDate, endDate *time.Time

	if req.StartDate != "" {
		sd, err := time.Parse("2006-01-02", req.StartDate)
		if err != nil {
			return nil, errors.New("开始日期格式错误")
		}
		startDate = &sd
	}

	if req.EndDate != "" {
		ed, err := time.Parse("2006-01-02", req.EndDate)
		if err != nil {
			return nil, errors.New("结束日期格式错误")
		}
		endDate = &ed
	}

	distribution, err := s.statsRepo.GetMemberDistribution(req.Dimension, startDate, endDate)
	if err != nil {
		return nil, err
	}

	var total int64
	for _, item := range distribution {
		total += item.Count
	}

	return &model.MemberDistributionResp{
		Dimension:    req.Dimension,
		Total:        total,
		Distribution: distribution,
	}, nil
}

// ==================== 课程统计实现 ====================

func (s *statisticsService) GetCourseRanking(req *model.CourseRankingReq) (*model.CourseRankingResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	orderBy := req.OrderBy
	if orderBy == "" {
		orderBy = "bookings"
	}

	limit := req.Limit
	if limit <= 0 {
		limit = 10
	}

	rankings, err := s.statsRepo.GetCourseRanking(startDate, endDate, orderBy, limit)
	if err != nil {
		return nil, err
	}

	return &model.CourseRankingResp{
		Period:   req.StartDate + " ~ " + req.EndDate,
		OrderBy:  orderBy,
		Rankings: rankings,
	}, nil
}

func (s *statisticsService) GetCourseBookingTrends(courseID *uint, req *model.StatisticsQueryReq) (*model.CourseBookingTrendsResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	groupBy := req.GroupBy
	if groupBy == "" {
		groupBy = "day"
	}

	return s.statsRepo.GetCourseBookingTrends(courseID, startDate, endDate, groupBy)
}

func (s *statisticsService) GetTimeslotStats(req *model.StatisticsQueryReq) (*model.TimeslotStatsResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	timeslotStats, err := s.statsRepo.GetTimeslotStats(startDate, endDate)
	if err != nil {
		return nil, err
	}

	// 找出高峰时段（预约量前3）
	var peakHours []int
	if len(timeslotStats) >= 3 {
		// 简单取前3个（已按小时排序）
		// TODO: 应该按预约量排序
		for i := 0; i < 3 && i < len(timeslotStats); i++ {
			peakHours = append(peakHours, timeslotStats[i].Hour)
		}
	}

	return &model.TimeslotStatsResp{
		Period:        req.StartDate + " ~ " + req.EndDate,
		TimeslotStats: timeslotStats,
		PeakHours:     peakHours,
	}, nil
}

// ==================== 教练统计实现 ====================

func (s *statisticsService) GetCoachWorkload(req *model.CoachWorkloadReq) (*model.CoachWorkloadResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	workloads, err := s.statsRepo.GetCoachWorkload(req.CoachID, startDate, endDate)
	if err != nil {
		return nil, err
	}

	// 计算汇总数据
	var totalCoaches int64
	var totalCourses, totalBookings int64
	var totalRating float64

	for _, w := range workloads {
		totalCoaches++
		totalCourses += w.TotalCourses
		totalBookings += w.TotalBookings
		totalRating += w.AvgRating
	}

	avgCoursesPerCoach := 0.0
	avgBookingsPerCoach := 0.0
	avgRating := 0.0

	if totalCoaches > 0 {
		avgCoursesPerCoach = float64(totalCourses) / float64(totalCoaches)
		avgBookingsPerCoach = float64(totalBookings) / float64(totalCoaches)
		avgRating = totalRating / float64(totalCoaches)
	}

	return &model.CoachWorkloadResp{
		Period:  req.StartDate + " ~ " + req.EndDate,
		Coaches: workloads,
		Summary: model.CoachWorkloadSummary{
			TotalCoaches:        totalCoaches,
			AvgCoursesPerCoach:  avgCoursesPerCoach,
			AvgBookingsPerCoach: avgBookingsPerCoach,
			AvgRating:           avgRating,
		},
	}, nil
}

func (s *statisticsService) GetCoachRanking(req *model.CourseRankingReq) (*model.CoachRankingResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	orderBy := req.OrderBy
	if orderBy == "" {
		orderBy = "bookings"
	}

	limit := req.Limit
	if limit <= 0 {
		limit = 10
	}

	rankings, err := s.statsRepo.GetCoachRanking(startDate, endDate, orderBy, limit)
	if err != nil {
		return nil, err
	}

	return &model.CoachRankingResp{
		Period:   req.StartDate + " ~ " + req.EndDate,
		OrderBy:  orderBy,
		Rankings: rankings,
	}, nil
}

// ==================== 营收统计实现 ====================

func (s *statisticsService) GetRevenueOverview(req *model.StatisticsQueryReq) (*model.RevenueOverviewResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	// 总营收
	totalRevenue, err := s.statsRepo.GetRevenueByDateRange(startDate, endDate)
	if err != nil {
		return nil, err
	}

	// 支付方式分布
	paymentMethods, err := s.statsRepo.GetRevenueByPaymentMethod(startDate, endDate)
	if err != nil {
		return nil, err
	}

	// 计算日均
	days := endDate.Sub(startDate).Hours() / 24
	if days == 0 {
		days = 1
	}
	dailyAvg := totalRevenue / days

	// 增长率（与上一周期对比）
	duration := endDate.Sub(startDate)
	lastPeriodStart := startDate.Add(-duration)
	lastPeriodEnd := startDate
	lastPeriodRevenue, _ := s.statsRepo.GetRevenueByDateRange(lastPeriodStart, lastPeriodEnd)

	growthRate := 0.0
	if lastPeriodRevenue > 0 {
		growthRate = (totalRevenue - lastPeriodRevenue) / lastPeriodRevenue * 100
	}

	return &model.RevenueOverviewResp{
		Period:          req.StartDate + " ~ " + req.EndDate,
		TotalRevenue:    totalRevenue,
		RechargeRevenue: totalRevenue, // 简化处理
		CardRevenue:     0,
		DailyAvg:        dailyAvg,
		GrowthRate:      growthRate,
		PaymentMethods:  paymentMethods,
	}, nil
}

func (s *statisticsService) GetRevenueTrends(req *model.RevenueQueryReq) (*model.RevenueTrendsResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	groupBy := req.GroupBy
	if groupBy == "" {
		groupBy = "day"
	}

	revenueType := req.Type
	if revenueType == "" {
		revenueType = "all"
	}

	trends, err := s.statsRepo.GetRevenueTrends(startDate, endDate, groupBy, revenueType)
	if err != nil {
		return nil, err
	}

	// 计算汇总
	var total, max, min float64
	min = -1

	for _, trend := range trends {
		total += trend.TotalRevenue
		if trend.TotalRevenue > max {
			max = trend.TotalRevenue
		}
		if min < 0 || trend.TotalRevenue < min {
			min = trend.TotalRevenue
		}
	}

	avg := 0.0
	if len(trends) > 0 {
		avg = total / float64(len(trends))
	}

	return &model.RevenueTrendsResp{
		Period:  req.StartDate + " ~ " + req.EndDate,
		GroupBy: groupBy,
		Type:    revenueType,
		Trends:  trends,
		Summary: model.RevenueSummary{
			Total: total,
			Avg:   avg,
			Max:   max,
			Min:   min,
		},
	}, nil
}

func (s *statisticsService) GetConsumptionStats(req *model.StatisticsQueryReq, consumeType *string) (*model.ConsumptionStatsResp, error) {
	startDate, err := time.Parse("2006-01-02", req.StartDate)
	if err != nil {
		return nil, errors.New("开始日期格式错误")
	}

	endDate, err := time.Parse("2006-01-02", req.EndDate)
	if err != nil {
		return nil, errors.New("结束日期格式错误")
	}

	return s.statsRepo.GetConsumptionStats(startDate, endDate, consumeType)
}
